package com.owg.jigsaw.javafx;

import owg.util.data.ReferenceSet;
import owg.util.data.Referencer;
import javafx.beans.property.ObjectProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.WeakChangeListener;
import javafx.geometry.Point2D;
import javafx.scene.Group;
import javafx.scene.effect.BlendMode;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.paint.Color;
import javafx.scene.paint.Paint;
import javafx.scene.shape.Rectangle;
import javafx.scene.transform.Rotate;

public class FXColoredImageView extends Group
{
	private final Rectangle colorizer;
	private Rectangle bgColorizer;
	private final ImageView imageView;
	private final ImageView rectClip;

	/**Garbage collection prevention*/
	private final Referencer referencer = new ReferenceSet();
	
	public FXColoredImageView(Image im, Color c, Color bgColor)
	{
		colorizer = new Rectangle(im.getWidth(), im.getHeight());
		colorizer.setFill(c);
		rectClip = new ImageView(im);
		colorizer.setClip(rectClip);
		getChildren().add(colorizer);
		imageView = new ImageView(im);
		imageView.setBlendMode(BlendMode.MULTIPLY);
		getChildren().add(imageView);
		setBGColor(bgColor);
		resize(im.getWidth(), im.getHeight());
	}
	/**Create a colored image view bound to the indicated image property.*/
	public FXColoredImageView(ObjectProperty<Image> imProp, Color c, Color bgColor)
	{
		this(imProp.get(), c, bgColor);
		ChangeListener<Image> imListener = ((prop, oldVal, newVal) -> 
		{
			imageView.setImage(newVal);
			colorizer.setWidth(newVal.getWidth());
			colorizer.setHeight(newVal.getHeight());
			rectClip.setImage(newVal);
		});
		//Prevent GC
		referencer.addReference(imListener);
		imProp.addListener(new WeakChangeListener<Image>(imListener));
	}

	private int getWidth()
	{
		return (int) colorizer.getWidth();
	}
	private int getHeight()
	{
		return (int) colorizer.getHeight();
	}

	public void setBGColor(Color bgColor)
	{
		if(bgColorizer != null)
			getChildren().remove(bgColorizer);
		
		if(bgColor != null)
		{
			bgColorizer = new Rectangle(0.5, 0.5, colorizer.getWidth()-1, colorizer.getHeight()-1);
			bgColorizer.setStroke(new Color(bgColor.getRed()/2, bgColor.getGreen()/2, bgColor.getBlue()/2, 1.0));
			bgColorizer.widthProperty().bind(colorizer.widthProperty());
			bgColorizer.heightProperty().bind(colorizer.heightProperty());
			bgColorizer.setFill(bgColor);
			getChildren().add(bgColorizer);
			bgColorizer.toBack();
		}
		else
			bgColorizer = null;
	}

	public Referencer referencer()
	{
		return referencer;
	}

	public boolean containsWithSlack(Point2D localPoint, int slack)
	{
		return localPoint.getX() >= -slack && localPoint.getX() < getWidth()+slack &&
			localPoint.getY() >= -slack && localPoint.getY() < getHeight()+slack;
	}
	/**Returns the image color property. Change this to colorize the image with a different color.*/
	public ObjectProperty<Paint> colorProperty()
	{
		return colorizer.fillProperty();
	}
	public void rotate(double degrees)
	{
		getTransforms().add(new Rotate(degrees, 0, 0));
	}
}
